package com.java.jvalidator.framework;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TypeUtil {
	private static final String GET_METHOD_PREFIX = "get";
	private static final String DOT = ".";
	private static final String DOT_PATTERN = "\\.";

	/***
	 * 取得对象的字段的值
	 * 
	 * @param target
	 * @param propertyName
	 * @return
	 * @throws ValidationException
	 */
	public static Object getPropertyValue(Object target, String propertyName) throws ValidationException {
		if ((target == null) || (isStringNullOrEmpty(propertyName))) {
			throw new ValidationException(ValidationExceptionMsg.VALIDATION_ERROR);
		}
		String[] propertyNameArray = propertyName.split(DOT_PATTERN);
		Object targetObj = target;
		for (String property : propertyNameArray) {
			Method m = retrieveGetMethod(targetObj, property);

			// 取到的getXXX方法为空时，直接通过申明的字段来取值
			if (m == null) {
				try {
					return getFieldValue(target, propertyName);
				} catch (NoSuchFieldException e) {
					throw new ValidationException(e);
				}
			}
			m.setAccessible(true);
			try {
				targetObj = m.invoke(targetObj, new Object[0]);
			} catch (IllegalArgumentException e) {
				throw new ValidationException(e);
			} catch (IllegalAccessException e) {
				throw new ValidationException(e);
			} catch (InvocationTargetException e) {
				throw new ValidationException(e);
			}
		}
		return targetObj;
	}

	/***
	 * getDeclaredFields()能访问类中所有的字段,与public,private,protect无关
	 * 所以，在无法构造出getXXX方法的时候，可以通过找类的fieldName取到该field的值
	 * 
	 * @param targetObject
	 * @param name
	 * @return
	 * @throws NoSuchFieldException
	 */
	public static Object getFieldValue(Object targetObject, String name) throws NoSuchFieldException {
		if ((targetObject == null) || (name == null)) {
			return null;
		}
		String[] fieldNameArray = name.split(DOT_PATTERN);
		Object targetObj = targetObject;
		Field field = null;
		for (int i = 0; i < fieldNameArray.length; i++) {
			try {
				// getDeclaredFields()能访问类中所有的字段,与public,private,protect无关
				field = targetObj.getClass().getDeclaredField(fieldNameArray[i]);
				if (field == null) {
					return null;
				}
				field.setAccessible(true);
				targetObj = field.get(targetObj);
			} catch (SecurityException e) {
				return null;
			} catch (IllegalArgumentException e) {
				return null;
			} catch (IllegalAccessException e) {
				return null;
			}
		}
		return targetObj;
	}

	/**
	 * 根据传入的对象和字段名得到get方法
	 * 
	 * @param target
	 * @param propertyName
	 * @return
	 * @throws ValidationException
	 */
	public static Method retrieveGetMethod(Object target, String propertyName) throws ValidationException {
		if ((target == null) || (isStringNullOrEmpty(propertyName))) {
			return null;
		}
		Object targetObj = target;
		String targetPropertyName = propertyName;

		if (propertyName.contains(DOT)) {
			// 例如
			// target是student对象，propertyName为class.name,其中class为学科对象，name为String
			// 第一层，通过student对象取到class，然后通过class对象取到name的值
			String[] propertyNameArray = propertyName.split(DOT_PATTERN);
			for (int i = 0; i < propertyNameArray.length - 1; i++) {
				String propName = propertyNameArray[i];
				Object propertyValue = getPropertyValue(target, propName);
				targetObj = propertyValue;
			}
			targetPropertyName = propertyNameArray[(propertyNameArray.length - 1)];
		}
		Class<? extends Object> targetClass = targetObj.getClass();

		Character firstCharacter = Character.valueOf(Character.toUpperCase(targetPropertyName.charAt(0)));
		try {
			// 构造get方法，这里要注意如果的是boolean字段，默认的使用ide生成getter的都是isXXX，需要自己手动调整
			String methodName = GET_METHOD_PREFIX + firstCharacter + targetPropertyName.substring(1);
			return targetClass.getMethod(methodName, new Class[0]);
		} catch (SecurityException e) {
			throw new ValidationException(e);
		} catch (NoSuchMethodException e) {
			// getFieldValue即可解决找不到getXXX方法的字段取值问题
		}
		return null;
	}

	/***
	 * 判断传入的对象是否是数字类型，包括：Byte,Short,Integer,Long,Float,Double
	 * 
	 * @param value
	 * @return
	 */
	public static boolean isDigital(Object value) {
		if (value == null) {
			return false;
		}

		return ((value instanceof Byte)) || ((value instanceof Short)) || ((value instanceof Integer)) 
				|| ((value instanceof Long)) || ((value instanceof Float)) || ((value instanceof Double));
	}

	/***
	 * trim String.<br />
	 * 如果传入值为null，则返回空字符串
	 * 
	 * @param s
	 * @return
	 */
	public static String trimString(String s) {
		if (s == null) {
			return "";
		}
		return s.trim();
	}

	/***
	 * 判断字符串是否为null或空<br />
	 * 如果为null或者长度为0,则返回true
	 * 
	 * @param string
	 * @return
	 */
	public static boolean isStringNullOrEmpty(String s) {
		return trimString(s).length() == 0;
	}

	/**
	 * 将传入的数字转成Double,如果传入的不是数值类型，则抛出异常
	 * @param value
	 * @return
	 * @throws ValidationException
	 */
	public static double convertNumberToDouble(Object value) throws ValidationException {
		if (isDigital(value)) {
			String digitalString = String.valueOf(value);
			return Double.parseDouble(digitalString);
		} else {
			throw new ValidationException("The object you passed isn't digital!");
		}
	}

//	/**
//	 * 
//	 * @param name
//	 * @param nameList
//	 * @return
//	 */
//	public static String getName(String name, List<String> nameList) {
//		int number = 1;
//
//		while (nameList.contains(name + "_" + number)) {
//			number++;
//		}
//		name = name + "_" + number;
//
//		return name;
//	}
}
